package com.tarena.lbs.basic.web.service;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.pagehelper.PageInfo;
import com.tarena.lbs.attach.api.AttachApi;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.basic.web.repository.AdminRepository;
import com.tarena.lbs.basic.web.repository.BusinessCategoryRepository;
import com.tarena.lbs.basic.web.repository.BusinessRepository;
import com.tarena.lbs.common.passport.enums.Roles;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.common.security.utils.LbsSecurityContenxt;
import com.tarena.lbs.pojo.attach.param.PicUpdateParam;
import com.tarena.lbs.pojo.basic.param.BusinessParam;
import com.tarena.lbs.pojo.basic.po.AdminPO;
import com.tarena.lbs.pojo.basic.po.BusinessCategoryPO;
import com.tarena.lbs.pojo.basic.po.BusinessPO;
import com.tarena.lbs.pojo.basic.query.BusinessQuery;
import com.tarena.lbs.pojo.basic.vo.BusinessCategoryVO;
import com.tarena.lbs.pojo.basic.vo.BusinessVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BusinessService {

    @Autowired
    private BusinessRepository businessRepository;
    @Autowired
    private BusinessCategoryRepository businessCategoryRepository;
    @Autowired
    private AdminRepository adminRepository;
    //采用pageHelper分页插件查询分页数据
    public PageResult<BusinessVO> businessPage(BusinessQuery query) throws BusinessException {
        //为店铺绑定商家 查询商家列表 引入数据权限业务逻辑
        //a.获取反问发起的用户 认证对象
        UserPrinciple userPrinciple = LbsSecurityContenxt.getLoginToken();
        // b.判断空 读取角色 根据角色判断是否查询=条件query 要补充businessId
        Asserts.isTrue(userPrinciple == null,new BusinessException("-2","用户解析认证失败"));
        Integer adminId = userPrinciple.getId();
        Roles roles = userPrinciple.getRole();
        if (roles==Roles.SHOP){
            AdminPO adminPO = adminRepository.getAdminById(adminId);
            Asserts.isTrue(adminPO==null,new BusinessException("-2","商家信息不存在"));
            query.setBusinessId(adminPO.getBusinessId());
        }
        //1.准备一个空的pageResult返回对象
        PageResult<BusinessVO> voPages = new PageResult<>();
        //2.调用仓储层查询数据库分页数据,返回值是PageInfo
        PageInfo<BusinessPO> pageInfo = businessRepository.businessPageHelper(query);
        log.info("分页查询商家信息，入参：{},返回结果：{}",query,pageInfo);
        //3.将pageInfo中的数据封装到voPages中
        voPages.setTotal(pageInfo.getTotal());//设置总记录数
        voPages.setPageNo(pageInfo.getPageNum());//设置当前页码
        voPages.setPageSize(pageInfo.getPageSize());//设置每页记录数
        //4.将pageInfo中的list数据封装到voPages中,判断list是否为空
        List<BusinessVO> vos = null;
        if (CollectionUtils.isNotEmpty(pageInfo.getList())){
            List<BusinessPO> pos = pageInfo.getList();
            vos = pos.stream().map(po->{
                BusinessVO vo = new BusinessVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList());
        }
        voPages.setObjects(vos);
        return voPages;
    }

//手搓分页查询
//    public PageResult<BusinessVO> businessPage(BusinessQuery query) {
//        //业务层 需要根据入参条件query 查询数据库的满足条件的商家数据,然后按照分页处理
//        PageResult<BusinessVO> voPages = new PageResult<>();
//        //voPages分页对象, 需要设置分页数据Objects(查询数据库)，总记录数total(查询数据库)，当前页码PageNo(请求入参传过来)，每页记录数PageSize(请求入参传过来)，总页数TotalPage(总记录数/每页记录数)
//        Long total = businessRepository.businessTotal(query);
//        voPages.setTotal(total);//设置总记录数
//        voPages.setPageNo(query.getPageNo());//设置当前页码
//        voPages.setPageSize(query.getPageSize());//设置每页记录数
//        List<BusinessVO> vos = null;
//        if (total > 0){
//            List<BusinessPO> pos = businessRepository.businessPage(query);
//            //将pos转成vos
//            /*这段代码使用Java 8的Stream API将BusinessPO对象列表转换为BusinessVO对象列表。
//            通过map方法，每个BusinessPO对象被转换为BusinessVO对象，
//            并使用BeanUtils.copyProperties复制属性，最后通过collect方法将结果收集到列表中
//             */
//            vos = pos.stream().map(po->{
//                BusinessVO vo = new BusinessVO();
//                BeanUtils.copyProperties(po,vo);
//                return vo;
//            }).collect(Collectors.toList());
//            /*for (BusinessPO po:pos){
//                BusinessVO vo = new BusinessVO();
//                BeanUtils.copyProperties(po,vo);
//                //vo添加到vos集合中
//            }*/
//        }
//        voPages.setObjects(vos);
//        log.info("分页查询商家信息，入参：{},返回结果：{}",query,voPages);
//        return voPages;
//    }

    public List<BusinessCategoryVO> getAllCats() {
        List<BusinessCategoryVO> vos = null;//如果没有数据查询结果,返回null
        //1.调用仓储层查询数据库所有行业分类数据 pos
        List<BusinessCategoryPO> pos = businessCategoryRepository.getAll();
        // 2.在pos不为空时,才将pos转成vos
        if (CollectionUtils.isNotEmpty(pos)){
            vos = pos.stream().map(po->{
                BusinessCategoryVO vo = new BusinessCategoryVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList());
        }
        return vos;
    }
    //本地事务注解 会因为商家绑定图片失败抛的业务异常BusinessException回滚,新增商家不成功
    //注解默认回滚的异常范围是RuntimeException类型

    /**
     * 新增商家
     * @param param
     * @throws BusinessException
     */
    @Transactional(rollbackFor = Exception.class)
    public void businessSave(BusinessParam param) throws BusinessException {
        //1.检查当前角色是否为Admin
        checkRole(Roles.ADMIN);
        //2.考虑幂等 不允许重复提交,不允许名称和电话相同
        BusinessPO po = businessRepository.getBusinessByName(param.getBusinessName());
        //3.如果po不为空,则不允许提交,使用Asserts断言抛出异常
        Asserts.isTrue(po!=null,new BusinessException("-2","商家已经存在"));
        //4.如果po为空,则允许提交,将param转成po
        BusinessPO poParam = businessParam2po(param);
        log.info("新增商家,新增前的id:{}",poParam.getId());
        //5.调用仓储层保存数据po
        businessRepository.save(poParam);
        log.info("新增商家,新增后的id:{}",poParam.getId());
        //6.新增商家后,远程绑定图片
        bindPicture(poParam);

    }

    //绑定图片
    @DubboReference
    private AttachApi attachApi;
    private void bindPicture(BusinessPO poParam) throws BusinessException {
        //1.根据poParam这个商家的数据,封装绑定图片的list
        //2.绑定几张 logo 营业执照 绑定给谁 当前商家 bizType=100 营业执照 bizType=200 logo bizId=businessId
        List<PicUpdateParam> picParams=new ArrayList<>();
        //封装营业执照图片的参数
        PicUpdateParam licensePic=new PicUpdateParam();
        licensePic.setBusinessId(poParam.getId());
        licensePic.setBusinessType(100);//100是营业执照 商家的
        String licenseFileUuid = getFileUuidFromUrl(poParam.getBusinessLicense());
        licensePic.setFileUuid(licenseFileUuid);
        picParams.add(licensePic);
        //封装logo图片的参数
        PicUpdateParam logoPic=new PicUpdateParam();
        logoPic.setBusinessId(poParam.getId());
        logoPic.setBusinessType(200);//200是logo 商家的
        String logoFileUuid = getFileUuidFromUrl(poParam.getBusinessLogo());
        logoPic.setFileUuid(logoFileUuid);
        picParams.add(logoPic);
        //验证图片绑定是否成功
        log.info("当前商家:{},绑定图片:{}",poParam.getBusinessName(),picParams);
        //发起远程调用进行图片绑定
        boolean result = attachApi.batchUpdateBusiness(picParams);
        //对返回值的处理 考虑分布式事务问题:考虑数据一致性问题,这里是强制一致性,图片绑定失败,不新增商家
        Asserts.isTrue(!result,new BusinessException("-2","图片绑定失败"));
    }

    //从url中截取fileUuid
    private String getFileUuidFromUrl(String url) {
        //拿到图片的id或者fileUuid 这里需要在数据库中找到url 截取fileUuid作为绑定入参
        //http://localhost:9081/static/liencesFileUuid
        String[] splits = url.split("/");
        return splits[splits.length-1];
    }

    //将param转成po
    private BusinessPO businessParam2po(BusinessParam param) {
        BusinessPO po = new BusinessPO();
        BeanUtils.copyProperties(param,po);
        po.setAuditRemarks("通过");
        //1待审核 2审核通过 3驳回(这种数字形式可能会出现业务填补错误,一般使用封装好的常量或者枚举)
        po.setBusinessStatus(2);
        po.setEntryTime(new Date());
        return po;
    }

    //检查当前登录用户角色是否为管理员
    private void checkRole(Roles roles) throws BusinessException {
        //使用断言,当前登录用户角色是否为管理员,不是则抛出异常
        UserPrinciple userPrinciple = LbsSecurityContenxt.getLoginToken();
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户认证解析失败"));
        //获取登录用户角色
        Roles loginRole = userPrinciple.getRole();
        Asserts.isTrue(loginRole!=roles,new BusinessException("-2","当前用户无权限"));
        log.info("当前用户角色：{}",loginRole);
    }
}
